package com.googlecode.hypersphere.xml;

import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import junit.framework.AssertionFailedError;
import junit.framework.ComparisonFailure;
import junit.framework.TestCase;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class XSDMock {

	
	public static void assertIsIdentical(Element element1, Element element2) {
		TestCase.assertEquals(element1.getName(), element2.getName());
		Map<String, Attribute> attributeMap1 = collectAttributes(element1);
		Map<String, Attribute> attributeMap2 = collectAttributes(element2);
		assertHasSameAttributes(attributeMap1, attributeMap2);
		Map<String, Element> childrenMap1 = collectChildren(element1);
		Map<String, Element> childrenMap2 = collectChildren(element2);
		assertHasSameChildren(childrenMap1, childrenMap2);
	}
 
	private static void assertHasSameChildren(Map<String, Element> map1, Map<String, Element> map2) {
		Iterator iterator2 = map2.keySet().iterator();
		for (Iterator iter = map1.keySet().iterator(); iter.hasNext();) {
			String name = (String) iter.next();
			Element child1 = map1.get(name);
			Element child2 = map2.get(name);
			TestCase.assertFalse(child1 == null);
			TestCase.assertFalse(child2 == null);
			assertIsIdentical(child1, child2);
			iterator2.next();
		}
		TestCase.assertFalse(iterator2.hasNext());
	}
	
	private static void assertHasSameAttributes(Map<String, Attribute> map1, Map<String, Attribute> map2) {
		Iterator iterator2 = map2.keySet().iterator();
		for (Iterator iter = map1.keySet().iterator(); iter.hasNext();) {
			String name = (String) iter.next();
			Attribute attribute1 = map1.get(name);
			Attribute attribute2 = map2.get(name);
			TestCase.assertFalse(attribute1 == null);
			TestCase.assertFalse(attribute2 == null);
			TestCase.assertEquals(attribute1.getValue(), attribute2.getValue());
			iterator2.next();
		}
		TestCase.assertFalse(iterator2.hasNext());
	}

	private static Map<String, Element> collectChildren(Element root) {
		Map<String, Element> map = new HashMap<String, Element>();
		for (Iterator iter = root.elementIterator(); iter.hasNext();) {
			Element element = (Element) iter.next();
			map.put(element.attributeValue("name") + element.attributeValue("ref"), element);
		}
		return map;
	}
	
	private static Map<String, Attribute> collectAttributes(Element root) {
		Map<String, Attribute> map = new HashMap<String, Attribute>();
		for (Iterator iter = root.attributeIterator(); iter.hasNext();) {
			Attribute attribute = (Attribute) iter.next();
			map.put(attribute.getName(), attribute);
		}
		return map;
	}

	public static void assertIsINotdentical(Element element1, Element element2) {
		try {
			XSDMock.assertIsIdentical(element1, element2);
			TestCase.fail();
		} catch (ComparisonFailure e) {
			// fine
		} catch (AssertionFailedError e) {
			// fine
		}
	}

	public static void assertIsIdentical(File xsdFile, Element xmlElement) {
		SAXReader xmlReader = new SAXReader();
		Document xsdDoc;
		try {
			xsdDoc = xmlReader.read(xsdFile);
		} catch (DocumentException e) {
			throw new IllegalArgumentException(e);
		}
		Element xsdElement = xsdDoc.getRootElement();
		XSDMock.assertIsIdentical(xsdElement, xmlElement);
	}
}
